<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>NMEAParser: NMEAParser Library</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectalign" style="padding-left: 0.5em;">
   <div id="projectname">NMEAParser
   </div>
   <div id="projectbrief">NMEA Parser Library - Monte Variakojis @VisualGPS</div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "search",false,'Search');
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
$(function() {
  initMenu('',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
</script>
<div id="main-nav"></div>
</div><!-- top -->
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div class="header">
  <div class="headertitle">
<div class="title">NMEAParser Library </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><h1>NMEA Parser Class Library</h1>
<p>Monte Variakojis @VisualGPS</p>
<h2>Introduction</h2>
<p>The NMEA 0813 standard for interfacing marine electronics devices specifies the NMEA data sentence structure as well as general definitions of approved sentences. However, the specification does not cover implementation and design. This article will hopefully clarify some of the design tasks needed to parse through NMEA sentences robustly. It will try to show techniques in parsing and data integrity checking. The article does assume that the reader has knowledge in software design and has experience in some sort of programming language. This article will reference the NMEA 0183 specification and it is recommended that the NMEA 0813 specification be available as a reference.</p>
<p>This article makes no assumption of the media that the NMEA data is acquired. The techniques here can be applied on received data from a higher abstraction layer. A simple example written in C++ demonstrates this parser design. Please note that the specific NMEA sentences parsed are centric to a GPS device.</p>
<h2>NMEA Protocol</h2>
<p>NMEA data is sent in 8-bit ASCII where the MSB is set to zero (0). The specification also has a set of reserved characters. These characters assist in the formatting of the NMEA data string. The specification also states valid characters and gives a table of these characters ranging from HEX 20 to HEX 7E.</p>
<p>As stated in the NMEA 0183 specification version 3.01 the maximum number of characters shall be 82, consisting of a maximum of 79 characters between start of message "$" or "!" and terminating delimiter &lt;CR&gt;&lt;LF&gt; (HEX 0D and 0A). The minimum number of fields is one (1).</p>
<h3>Basic sentence format:</h3>
<div class="fragment"><div class="line">$aaccc,c--c*hh&lt;CR&gt;&lt;LF&gt;</div><div class="line">    $           Start of sentence</div><div class="line">    aaccc       Address field/Command</div><div class="line">    ,           Field delimiter (Hex 2C)</div><div class="line">    c--c        Data sentence block</div><div class="line">    *           Checksum delimiter (HEX 2A)</div><div class="line">    hh          Checksum field (the hexadecimal value represented in ASCII)</div><div class="line">    &lt;CR&gt;&lt;LF&gt;    End of sentence (HEX OD OA)</div></div><!-- fragment --><h3>NMEA Parser</h3>
<p>Most protocols have a state machine tracking the protocol state and any errors that may occur during the data transfer. The NMEA parser we are discussing is based on a simple state machine. By using a state machine the computer can easily keep track of where it is within the protocol as well as recover from any errors such as timeouts and checksum errors.</p>
<p>The parsing example is designed such that a buffer can be sent to the parser along with the buffer length to maximize the computer processor efficiency. This will allow the computer to parse data when it is received. Since NMEA data is typically sent at 4800 baud, computers are often waiting for data. By having a state machine in place, partial or complete sets of NMEA data may be parsed. If only a partial set of data was received and sent to the parser, then when the rest of the data is received, the parser will complete any NMEA sentence that may have been incomplete.</p>
<p>Below, Figure 1 illustrates the data flow to the NMEA parser. Our design will assume two abstract software layers, NMEA protocol parser and specific NMEA sentence parser. It does not matter the number of data bytes received or if there is only a partial message. The NMEA parser will manage the data and extract individual NMEA sentences.</p>
<div class="dotgraph">
<img src="dot_inline_dotgraph_2.png" alt="dot_inline_dotgraph_2.png" border="0" usemap="#dot_inline_dotgraph_2.map"/>
<map name="dot_inline_dotgraph_2.map" id="dot_inline_dotgraph_2.map"></map>
<div class="caption">
[ figure 1 ]</div>
</div>
<h2>How it Works</h2>
<p>The NMEAParser class is composed of two main classes and individual NMEA sentence classes.</p>
<div class="dotgraph">
<img src="dot_inline_dotgraph_3.png" alt="dot_inline_dotgraph_3.png" border="0" usemap="#dot_inline_dotgraph_3.map"/>
<map name="dot_inline_dotgraph_3.map" id="dot_inline_dotgraph_3.map"><area shape="rect" id="node1" href="class_c_n_m_e_a_parser.html" title="CNMEAParser" alt="" coords="26,101,133,149"/>
<area shape="rect" id="node2" href="class_c_n_m_e_a_parser_packet.html" title="CNMEAParserPacket" alt="" coords="5,5,153,53"/>
</map>
<div class="caption">
Figure 2 - Class Hierarchy</div>
</div>
<p>The <a class="el" href="class_c_n_m_e_a_parser_packet.html" title="This class will parse NMEA data packet and call its virtual processor methods. ">CNMEAParserPacket</a> does the work of parsing the actual packet from a buffer of data. The data is feed into the state machine using the <a class="el" href="class_c_n_m_e_a_parser_packet.html#a1e4e876a492b6cd7e4665081da4ac443" title="Parses pData for NMEA data. ">CNMEAParserPacket::ProcessNMEABuffer()</a> method. This method will parse through the data, verify the checksum (if present) and call the virtual method <a class="el" href="class_c_n_m_e_a_parser_packet.html#a1da7aea129ff4ca1eefb07c82df30ecf" title="Redefine this method to process valid NMEA commands. Make sure that you honer the parameters below...">CNMEAParserPacket::ProcessRxCommand()</a>. The <a class="el" href="class_c_n_m_e_a_parser.html" title="This class will parse NMEA data, store its data and report that it has received data. ">CNMEAParser</a> class is based from the <a class="el" href="class_c_n_m_e_a_parser_packet.html" title="This class will parse NMEA data packet and call its virtual processor methods. ">CNMEAParserPacket</a>, redefines the ProcessRxCommand() method, and actual parse the specific NMEA sentence.</p>
<h2>Packet Parser State Machine - <a class="el" href="class_c_n_m_e_a_parser_packet.html#a1e4e876a492b6cd7e4665081da4ac443" title="Parses pData for NMEA data. ">CNMEAParserPacket::ProcessNMEABuffer()</a></h2>
<p>Located in the <a class="el" href="class_c_n_m_e_a_parser_packet.html#a1e4e876a492b6cd7e4665081da4ac443" title="Parses pData for NMEA data. ">CNMEAParserPacket::ProcessNMEABuffer()</a> method, the state machine will parse the incoming buffer weather it’s one byte or contains multiple NMEA sentences. Below describes the packet parsing states for a NMEA sentence.</p>
<div class="dotgraph">
<img src="dot_inline_dotgraph_4.png" alt="dot_inline_dotgraph_4.png" border="0" usemap="#dot_inline_dotgraph_4.map"/>
<map name="dot_inline_dotgraph_4.map" id="dot_inline_dotgraph_4.map"><area shape="poly" id="node1" href="class_c_n_m_e_a_parser_packet.html#afe77fde5b858aa74d2393ebdb9699cfc" title="1\nPARSE_STATE_SOM" alt="" coords="447,34,441,25,426,17,402,11,372,7,339,5,306,7,276,11,252,17,237,25,232,34,237,42,252,50,276,57,306,61,339,62,372,61,402,57,426,50,441,42"/>
<area shape="poly" id="node2" href="class_c_n_m_e_a_parser_packet.html#afe77fde5b858aa74d2393ebdb9699cfc" title="2\nPARSE_STATE_CMD" alt="" coords="291,140,286,131,271,123,247,117,217,113,184,111,151,113,122,117,98,123,83,131,78,140,83,148,98,156,122,162,151,166,184,168,217,166,247,162,271,156,286,148"/>
<area shape="poly" id="node3" href="class_c_n_m_e_a_parser_packet.html#afe77fde5b858aa74d2393ebdb9699cfc" title="3\nPARSE_STATE_DATA" alt="" coords="295,245,289,237,274,229,249,223,219,219,184,217,150,219,120,223,95,229,80,237,74,245,80,254,95,262,120,268,150,272,184,274,219,272,249,268,274,262,289,254"/>
<area shape="poly" id="node4" href="class_c_n_m_e_a_parser_packet.html#afe77fde5b858aa74d2393ebdb9699cfc" title="4\nPARSE_STATE_CHECKSUM_1" alt="" coords="401,351,394,343,373,335,340,328,298,324,252,323,206,324,165,328,132,335,111,343,103,351,111,360,132,368,165,374,206,378,252,380,298,378,340,374,373,368,394,360"/>
<area shape="rect" id="node6" href="class_c_n_m_e_a_parser_packet.html#a1da7aea129ff4ca1eefb07c82df30ecf" title="Call Virtual ProcessRxCommand" alt="" coords="221,563,433,611"/>
<area shape="poly" id="node5" href="class_c_n_m_e_a_parser_packet.html#afe77fde5b858aa74d2393ebdb9699cfc" title="5\nPARSE_STATE_CHECKSUM_2" alt="" coords="476,485,469,476,448,469,415,462,373,458,327,457,281,458,240,462,207,469,185,476,178,485,185,494,207,502,240,508,281,512,327,514,373,512,415,508,448,502,469,494"/>
</map>
<div class="caption">
Receive Packet State Machine</div>
</div>
<h3>State machine state definitions:</h3>
<ol type="1">
<li>Search for Start of Message (SOM). This state will look for the '$' (HEX 24) character. When the SOM is found, then the only transition is to get the NMEA address field or what I call the command.</li>
<li>Retrieve address field (command). The parser will collect characters until it encounters a ',' (comma HEX 2C) character. We are leaving the address field flexible length. This will allow parsing of any strange or proprietary sentences.</li>
<li>Retrieve sentence data. This is where all of the data associated with the NMEA address is collected for further parsing. This state will continue to collect data and perform a checksum calculation until it receives a checksum delimiter '*' (HEX 2A) or sentence terminator &lt;CR&gt;&lt;LF&gt; (HEX 0D 0A).</li>
<li>Receive first checksum ASCII character. This state simply waits for the first checksum character.</li>
<li>Receive second checksum ASCII character. When the second checksum character is received, there should be enough information to verify the received checksum to the calculated checksum that was preformed in state 3. If the checksums match, then only other task to do is check for the sentence terminator.</li>
</ol>
<p>When a complete NMEA command sentence is received, the virtual method <a class="el" href="class_c_n_m_e_a_parser_packet.html#a1da7aea129ff4ca1eefb07c82df30ecf" title="Redefine this method to process valid NMEA commands. Make sure that you honer the parameters below...">CNMEAParserPacket::ProcessRxCommand()</a> is called. This method is redefined in the <a class="el" href="class_c_n_m_e_a_parser.html" title="This class will parse NMEA data, store its data and report that it has received data. ">CNMEAParser</a> class and will parse the command, data, and stuff them into the correct CNMESentence object.</p>
<h4>Timeouts</h4>
<p>Timeouts can be handled at a higher level. If for some reason data has not been received for a specified period of time, the software can reset the NMEA Parser by calling the <a class="el" href="class_c_n_m_e_a_parser_packet.html#a1355525f6efa8d5584f856c2b59309a3" title="Reset the parser. ">CNMEAParserPacket::Reset()</a> method.</p>
<h2>Source Code</h2>
<p>NMEAParserLib is a C++ class library that will accept variable length data and parse a NMEA stream. Even though the code is written in C++, it only uses inherencies and virtual methods.</p>
<h2>Features</h2>
<ul>
<li>No outside library dependencies.</li>
<li>OS independent (no OS specific calls)</li>
<li>Abstract software synchronization. You can redefine the data lock virtual method to support your OS specific semaphore or mutex functions.</li>
<li>NMEA sentence notification. Redefine method to get notified that a new NMEA sentence was processed.</li>
</ul>
<h2>Required and Optional Tools</h2>
<ul>
<li>cmake - Build environment. See <a href="https://cmake.org">https://cmake.org</a></li>
<li>C++ 11 complaint compiler (Linux gcc or MS Windows VisualStudio)</li>
<li>doxygen (for documentation, optional but recommended) - <a href="http://www.stack.nl/~dimitri/doxygen/">http://www.stack.nl/~dimitri/doxygen/</a></li>
<li>graphviz (for documentation, optional but recommended) - <a href="http://graphviz.org/">http://graphviz.org/</a></li>
<li>Qt 5.8 (optional) - <a href="https://www.qt.io/">https://www.qt.io/</a> Qt is a cross platform graphical interface tool that will allow you to build comprehensive GUI application. The source code also includes a Qt project that uses the NMEAParser, displays position status, satellite azimuth/elevation, and signal quality graphically.</li>
</ul>
<h2>Build</h2>
<ul>
<li>Linux: <div class="fragment"><div class="line">$ mkdir ./NMEAParserBuild</div><div class="line">$ cd NMEAParserBuild</div><div class="line">$ cmake ../Software</div><div class="line">$ make</div><div class="line">$ make doc</div></div><!-- fragment --></li>
<li>Windows: <div class="fragment"><div class="line">[code was cloned to c:\Source\NMEAParser]</div><div class="line">c:\Source\NMEAParser&gt;mkdir ./NMEAParserBuild</div><div class="line">c:\Source\NMEAParser&gt;cd NMEAParserBuild</div><div class="line">c:\Source\NMEAParser\NMEAParserBuild&gt;cmake ../Software</div><div class="line">[Run VisualStudio and build as normal]</div></div><!-- fragment --></li>
</ul>
<h2>Usage</h2>
<p>Below is a basic program that defines a <a class="el" href="class_c_n_m_e_a_parser.html" title="This class will parse NMEA data, store its data and report that it has received data. ">CNMEAParser</a> object and streams NMEA data from a text file.</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include &lt;stdio.h&gt;</span></div><div class="line"><span class="preprocessor">#include &lt;<a class="code" href="_n_m_e_a_parser_8h.html">NMEAParser.h</a>&gt;</span></div><div class="line"><span class="comment"></span></div><div class="line"><span class="comment">///</span></div><div class="line"><span class="comment">/// \class MyParser</span></div><div class="line"><span class="comment">/// \brief child class of CNMEAParser which will redefine notification calls from the parent class.</span></div><div class="line"><span class="comment">///</span></div><div class="line"><span class="comment"></span><span class="keyword">class </span>MyNMEAParser : <span class="keyword">public</span> <a class="code" href="class_c_n_m_e_a_parser.html">CNMEAParser</a> {</div><div class="line"><span class="comment"></span></div><div class="line"><span class="comment">    ///</span></div><div class="line"><span class="comment">    /// \brief This method is called whenever there is a parsing error.</span></div><div class="line"><span class="comment">    ///</span></div><div class="line"><span class="comment">    /// Redefine this method to capture errors.</span></div><div class="line"><span class="comment">    ///</span></div><div class="line"><span class="comment">    /// \param pCmd Pointer to NMEA command that caused the error. Please note that this</span></div><div class="line"><span class="comment">    /// parameter may be NULL of not completely defined. Use with caution.</span></div><div class="line"><span class="comment">    ///</span></div><div class="line"><span class="comment"></span>    <span class="keyword">virtual</span> <span class="keywordtype">void</span> <a class="code" href="class_c_n_m_e_a_parser_packet.html#acbe37d75ecda1cda2ddd3245eea6db8a">OnError</a>(<a class="code" href="namespace_c_n_m_e_a_parser_data.html#a88b2365ba47855c3b8cfb7dfd71d99a9">CNMEAParserData::ERROR_E</a> nError, <span class="keywordtype">char</span> *pCmd) {</div><div class="line">        printf(<span class="stringliteral">&quot;ERROR for Cmd: %s, Number: %d\n&quot;</span>, pCmd, nError);</div><div class="line">    }</div><div class="line"></div><div class="line"><span class="keyword">protected</span>:<span class="comment"></span></div><div class="line"><span class="comment">    ///</span></div><div class="line"><span class="comment">    /// \brief This method is redefined from CNMEAParserPacket::ProcessRxCommand(char *pCmd, char *pData)</span></div><div class="line"><span class="comment">    ///</span></div><div class="line"><span class="comment">    /// \param pCmd Pointer to the NMEA command string</span></div><div class="line"><span class="comment">    /// \param pData Comma separated data that belongs to the command</span></div><div class="line"><span class="comment">    /// \return Returns CNMEAParserData::ERROR_OK If successful</span></div><div class="line"><span class="comment">    ///</span></div><div class="line"><span class="comment"></span>    <span class="keyword">virtual</span> <a class="code" href="namespace_c_n_m_e_a_parser_data.html#a88b2365ba47855c3b8cfb7dfd71d99a9">CNMEAParserData::ERROR_E</a> <a class="code" href="class_c_n_m_e_a_parser.html#ac661ec8031503ce2bb324ee011debea4">ProcessRxCommand</a>(<span class="keywordtype">char</span> *pCmd, <span class="keywordtype">char</span> *pData) {</div><div class="line"></div><div class="line">        <span class="comment">// Call base class to process the command</span></div><div class="line">        <a class="code" href="class_c_n_m_e_a_parser.html#ac661ec8031503ce2bb324ee011debea4">CNMEAParser::ProcessRxCommand</a>(pCmd, pData);</div><div class="line"></div><div class="line">        printf(<span class="stringliteral">&quot;Cmd: %s\nData: %s\n&quot;</span>, pCmd, pData);</div><div class="line">        <span class="keywordflow">return</span> <a class="code" href="namespace_c_n_m_e_a_parser_data.html#a88b2365ba47855c3b8cfb7dfd71d99a9a1cc61da760414f811f7163bb5ecf5470">CNMEAParserData::ERROR_OK</a>;</div><div class="line">    }</div><div class="line">};</div><div class="line"></div><div class="line"><span class="keywordtype">int</span> main(<span class="keywordtype">int</span> argc, <span class="keywordtype">char</span> *argv[], <span class="keywordtype">char</span> *envp[]) {</div><div class="line"></div><div class="line">    FILE *fp;</div><div class="line">    MyNMEAParser    NMEAParser;</div><div class="line"></div><div class="line">    <span class="comment">//</span></div><div class="line">    <span class="comment">// Make sure that we have enough parameters</span></div><div class="line">    <span class="comment">//</span></div><div class="line">    <span class="keywordflow">if</span> (argc &lt; 2) {</div><div class="line">        printf(<span class="stringliteral">&quot;Usage: NMEAParserTest [file]\n&quot;</span>);</div><div class="line">        <span class="keywordflow">return</span> -1;</div><div class="line">    }</div><div class="line"></div><div class="line">    <span class="comment">//</span></div><div class="line">    <span class="comment">// Open the NMEA file, fail if cannot open</span></div><div class="line">    <span class="comment">//</span></div><div class="line">    fp = fopen(argv[1], <span class="stringliteral">&quot;r&quot;</span>);</div><div class="line">    <span class="keywordflow">if</span> (fp == NULL) {</div><div class="line">        printf(<span class="stringliteral">&quot;Could not open file: %s\n&quot;</span>, argv[1]);</div><div class="line">        <span class="keywordflow">return</span> -1;</div><div class="line">    }</div><div class="line"></div><div class="line">    <span class="comment">//</span></div><div class="line">    <span class="comment">// Read the file and process</span></div><div class="line">    <span class="comment">//</span></div><div class="line">    <span class="keywordtype">char</span> pBuff[1024];</div><div class="line">    <span class="keywordflow">while</span> (feof(fp) == 0) {</div><div class="line">        <span class="keywordtype">size_t</span> nBytesRead = fread(pBuff, 1, 512, fp);</div><div class="line"></div><div class="line">        <a class="code" href="namespace_c_n_m_e_a_parser_data.html#a88b2365ba47855c3b8cfb7dfd71d99a9">CNMEAParserData::ERROR_E</a> nErr;</div><div class="line">        <span class="keywordflow">if</span> ((nErr = NMEAParser.ProcessNMEABuffer(pBuff, nBytesRead)) != <a class="code" href="namespace_c_n_m_e_a_parser_data.html#a88b2365ba47855c3b8cfb7dfd71d99a9a1cc61da760414f811f7163bb5ecf5470">CNMEAParserData::ERROR_OK</a>) {</div><div class="line">            printf(<span class="stringliteral">&quot;NMEA Parser ProcessNMEABuffer Failed and returned error: %d\n&quot;</span>, nErr);</div><div class="line">            fclose(fp);</div><div class="line">            <span class="keywordflow">return</span> -1;</div><div class="line">        }</div><div class="line">    }</div><div class="line"></div><div class="line">    fclose(fp);</div><div class="line">    <span class="keywordflow">return</span> 0;</div><div class="line">}</div></div><!-- fragment --> </div></div><!-- contents -->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/>
</a> 1.8.13
</small></address>
</body>
</html>
